#pragma once

#include "Business/ClassicArbitrageContracts.h"
#include "Business/ArbitrageLegs.h"
#include "Business/Policy/ClassicBusinessPosition.h"
#include "Business/DealingHistory.h"

class ClassicBusinessArgument
{
public:

	enum TYPE {AUTO,BOTH,JUST_BEARISH,JUST_BULLISH};

	ClassicBusinessArgument(ArbitrageContracts const& contract,
		double openBalance, double profitBalance,
		int maxOpenQuantity)
		:m_type(AUTO),m_contract(contract),m_openBalance(openBalance),m_profitBalance(profitBalance),
		m_bearish(Band::CreateBearish()),m_bullish(Band::CreateBullish()),m_maxOpenQuantity(maxOpenQuantity)
	{
	}

	ClassicBusinessArgument(ArbitrageContracts const& contract,
		Band const& bearish, 
		Band const& bullish, 
		int maxOpenQuantity)
	:m_type(BOTH),m_contract(contract),m_openBalance(0),m_profitBalance(0),
	m_bearish(bearish),m_bullish(bullish),m_maxOpenQuantity(maxOpenQuantity)
	{
	}
	ClassicBusinessArgument(ArbitrageContracts const& contract,
		Band const& band, 
		int maxOpenQuantity)
		:m_type(band.IsSameType(Band::CreateBearish()) ? JUST_BEARISH : JUST_BULLISH),
		m_contract(contract),m_openBalance(0),m_profitBalance(0),
		m_bearish(m_type == JUST_BEARISH ? band : Band::CreateBearish()),
		m_bullish(m_type == JUST_BULLISH ? band : Band::CreateBullish()),
		m_maxOpenQuantity(maxOpenQuantity)
	{
	}
	ClassicBusinessArgument(ClassicBusinessArgument const& other)
		:m_type(other.m_type),
		m_contract(other.m_contract),m_openBalance(other.m_openBalance),m_profitBalance(other.m_profitBalance),
		m_bearish(other.m_bearish),
		m_bullish(other.m_bullish),
		m_maxOpenQuantity(other.m_maxOpenQuantity)
	{
	}

	int GetType() const { return m_type; }
	ArbitrageContracts const& GetContracts() const { return m_contract; }
	double GetOpenBalance() const { return m_openBalance; }
	double GetProfitBalance() const { return m_profitBalance; }
	Band const& GetBearish() const { return m_bearish; }
	Band const& GetBullish() const { return m_bullish; }
	int GetMaxOpenQuantity() const { return m_maxOpenQuantity; }

	int GetMajor() const {return m_contract.GetMajor();}
	int GetMinor() const {return m_contract.GetMinor();}

	void UpdateBearish(Band const& band)
	{
		if (m_bearish.IsSameType(band))
		{
			m_bearish = band;
		}
	}

	void UpdateBullish(Band const& band)
	{
		if (m_bullish.IsSameType(band))
		{
			m_bullish = band;
		}
	}

	void UpdateByBollinger(Bollinger const& bollinger)
	{
		m_bearish.UpdateByBollinger(bollinger);
		m_bullish.UpdateByBollinger(bollinger);
	}

	void SetOpenBalance(double openBalance)
	{
		m_openBalance = openBalance;
	}

	void SetProfitBalance(double profitBalance)
	{
		m_profitBalance = profitBalance;
	}
private:
	int m_type;
	ArbitrageContracts m_contract;
	double m_openBalance;
	double m_profitBalance;
	Band m_bearish;
	Band m_bullish;
	int m_maxOpenQuantity;
};

class Customer;
class Business;
class MarketStorage;
class QueueContext;
class DealingRepository;
class CancellationRepository;
class Cancellation;
class RequestTimeout;
class Bollingers;

class ClassicBusinessContext
{
public:
	ClassicBusinessContext(Customer& customer,
		Business& business,
		ClassicBusinessArgument const& argument,
		MarketStorage const& marketStorage,
		QueueContext& queueContext,
		DealingRepository& dealingRepository,
		CancellationRepository& cancellingRepository
		);

	~ClassicBusinessContext();

	ClassicBusinessArgument const& GetArgument() const {return m_argument;}
	ClassicBusinessPosition const& GetPosition() const { return m_position; }
	bool IsEditable() const;
	bool IsOpened() const;
	char const* GetCurrentStatusName() const;
	double GetProfit() const;

	int GetMajor() const {return m_argument.GetMajor();}
	int GetMinor() const {return m_argument.GetMinor();}
	char const* GetMajorCode() const;
	char const* GetMinorCode() const;
	Business* GetBusiness() const { return &m_business; }

	void Init();
	void Start();
	void Stop();
	void Edit();
	void Clear();
	void UpdateBand(Band const& bearishBand, Band const& bullishBand);
	void UpdateBandByBollinger();

	int GetMinorOpenLocalId() const;
	int GetMajorOpenLocalId() const;

	bool IsMinorOpenOrdered() const;
	bool IsMajorOpenOrdered() const;

	bool IsLostOpenMarket() const;
	bool IsOpenMarket() const;

	bool IsOffsetCompleted() const;
	bool IsOffsetAllSuccess() const;

	bool IsMarketCloseLimit() const;
	bool TryOpen();

	void OnMinorMarket();

	void OpenMinor();
	void CancelMinorOpen();
	void OffsetMinorByLimitPrice(int quantity);

	void OffsetMinorByNormalPrice();
	void CancelMinorOffset();
	void OffsetMajorByLimitPrice();

	void OpenMajor();
	void CancelMajorOpen();
	void OffsetMajorByLimitPrice(int quantity);

	void OffsetAllMinor();
	void OffsetOverMinorByLimitPrice();
// 	void Offset();
	void OffsetAll();

	void FreezeMajorFunds();
	void UnfreezeMajorFunds();

	void OnMarket(Market const& market);
	void OnDealing(Dealing const& dealing);
	void OnTimeout(RequestTimeout const& timeout);
	void OnTrade(Trade const& trade);

	ArbitrageLegs const& GetCurrrentLegs() const { return *m_currrentLegs; }
	ArbitrageLegs const* GetCurrrentLegsPointer() const { return m_currrentLegs; }

	int GetMinorOpenQuantity() const { return m_minorOpenQuantity; }

	void SetBollingers(Bollingers const* bollingers) { m_bollingers = bollingers; }

	void UpdateBalance(double openBalance, double profitBalance);

	bool HasSamePosition() const;
	bool IsZero() const;

private:
	bool HasEnoughFunds(ArbitrageLegs const& legs, int& outCanOpenQuantity);
	enum PriceType {LIMIT,NORMAL};
	Order CreateOrder(Leg const& leg, int quantity,PriceType priceType) const;
	Dealing& PushOrder(Order const& order);
	Cancellation& PushCancellation(Cancellation const& cancellation);

	bool ValidateDealing(Dealing const& dealing) const;

	Customer& m_customer;
	Business& m_business;
	ClassicBusinessArgument m_argument;
	MarketStorage const& m_marketStorage;
	QueueContext& m_queueContext;
	DealingRepository& m_dealingRepository;
	CancellationRepository& m_cancellingRepository;

	ArbitrageLegs m_bearishLegs;
	ArbitrageLegs m_bullishLegs;
	ArbitrageLegs const* m_currrentLegs;
	class StatusMachine;
	std::tr1::shared_ptr<StatusMachine> m_machine;
	ClassicBusinessPosition m_position;

	int m_minorOpenQuantity;
	
	DealingHistory m_minorOpenHistory;
	DealingHistory m_majorOpenHistory;
	DealingHistory m_minorOffsetHistory;
	DealingHistory m_majorOffsetHistory;

	Bollingers const* m_bollingers;
};
